//! import "common\Base.j"

library MD5 requires Base

globals
	private string StringMap = "0123456789ABCDEF"
	private integer array M
	private integer array S
	private integer T = 0
	private integer array result
endglobals

function HexString takes integer i returns string
	local string str = ""
	local integer n = 8
	local integer index
	loop
		exitwhen n == 0
		set index = i - i / 16 * 16
		set str = SubString(StringMap,index,index + 1) + str
		set i = i / 16
		set n = n - 1
	endloop
	return str
endfunction

private function A takes nothing returns integer
	return 0x01234567
endfunction

private function B takes nothing returns integer
	return 0x89abcdef
endfunction

private function C takes nothing returns integer
	return 0xfedcba98
endfunction

private function D takes nothing returns integer
	return 0x76543210
endfunction

private function Anti takes integer i returns integer
	return -i - 1
endfunction

private function Earse takes integer i returns integer
	return 0x7fffffff - Anti(i)
endfunction

private function Addon takes integer i returns integer
	return Anti(0x7fffffff - i)
endfunction

private function Unm takes integer i returns integer
	if i > 0 then
		return Addon(i)
	else
		return Earse(i)
	endif
endfunction

private function Or takes integer x,integer y returns integer
	local integer sum = 0
	local integer pow = 1
	local integer i
	local integer j
	local boolean unm = false
	if x < 0 then
		set unm = true
		set x = Unm(x)
	endif
	if y < 0 then
		set unm = true
		set y = Unm(y)
	endif
	loop
		exitwhen x == 0 and y == 0
		set i = x - x / 2 * 2
		set j = y - y / 2 * 2
		if not(i == 0 and j == 0) then
			set sum = sum + pow
		endif
		set pow = pow * 2
		set x = x / 2
		set y = y / 2
	endloop
	if unm then
		set sum = Unm(sum)
	endif
	return sum
endfunction

private function And takes integer x,integer y returns integer
	return Anti(Or(Anti(x),Anti(y)))
endfunction

private function Xor takes integer x,integer y returns integer
	return Or(And(x,Anti(y)),And(Anti(x),y))
endfunction

private function F takes integer x,integer y,integer z returns integer
	local integer sum = 0
	local integer pow = 1
	local integer i
	local integer j
	local integer k
	loop
		exitwhen x == 0 and y == 0 and z == 0
		set i = x - x / 2 * 2
		set j = y - y / 2 * 2
		set k = z - z / 2 * 2
		if i == 0 then
			set sum = sum + k * pow
		else
			set sum = sum + j * pow
		endif
		set pow = pow * 2
		set x = x / 2
		set y = y / 2
		set z = z / 2
	endloop
	return sum
endfunction

private function G takes integer x,integer y,integer z returns integer
	local integer sum = 0
	local integer pow = 1
	local integer i
	local integer j
	local integer k
	loop
		exitwhen x == 0 and y == 0 and z == 0
		set i = x - x / 2 * 2
		set j = y - y / 2 * 2
		set k = z - z / 2 * 2
		if k == 0 then
			set sum = sum + j * pow
		else
			set sum = sum + i * pow
		endif
		set pow = pow * 2
		set x = x / 2
		set y = y / 2
		set z = z / 2
	endloop
	return sum
endfunction

private function H takes integer x,integer y,integer z returns integer
	local integer sum = 0
	local integer pow = 1
	local integer i
	local integer j
	local integer k
	loop
		exitwhen x == 0 and y == 0 and z == 0
		set i = x - x / 2 * 2
		set j = y - y / 2 * 2
		set k = z - z / 2 * 2
		set i = i + j + k
		if i == 1 or i == 3 then
			set sum = sum + pow
		endif
		set pow = pow * 2
		set x = x / 2
		set y = y / 2
		set z = z / 2
	endloop
	return sum
endfunction

private function I takes integer x,integer y,integer z returns integer
	local integer sum = 0
	local integer pow = 1
	local integer i
	local integer j
	local integer k
	loop
		exitwhen x == 0 and y == 0 and z == 0
		set i = x - x / 2 * 2
		set j = y - y / 2 * 2
		set k = z - z / 2 * 2
		if j != 0 and (i != 0 or k == 0) then
			set sum = sum + pow
		endif
		set pow = pow * 2
		set x = x / 2
		set y = y / 2
		set z = z / 2
	endloop
	return sum
endfunction

function md5 takes string s returns string
	local integer index
	local integer indexEnd
	local integer length
	local integer a
	local integer b
	local integer c
	local integer d
	local integer AA
	local integer BB
	local integer CC
	local integer DD
	local string r
	loop
		exitwhen T == 0
		set T = T - 1
		set S[T] = 0
	endloop
	set index = 0
	set length = StringLength(s)
	set indexEnd = length
	loop
		exitwhen index == indexEnd
		set S[T] = String2Id(SubString(s,index,index + 1))
		set T = T + 1
		set index = index + 1
	endloop
	set indexEnd = indexEnd - indexEnd / 64 * 64
	if indexEnd > 56 then
		set indexEnd = 56 + 64 - indexEnd
	else
		set indexEnd = 56 - indexEnd
	endif
	if indexEnd > 0 then
		set S[T] = 0x80000000
		set T = T + 1
		set index = 1
		loop
			exitwhen index >= indexEnd
			set index = index + 1
			set S[T] = 0
			set T = T + 1
		endloop
	endif
	set S[T] = 0
	set T = T + 1
	set S[T] = 0
	set T = T + 1
	set S[T] = 0
	set T = T + 1
	set S[T] = 0
	set T = T + 1
	set S[T] = length / 0x1000000
	set T = T + 1
	set length = length - length / 0x1000000 * 0x1000000
	set S[T] = length / 0x10000
	set T = T + 1
	set length = length - length / 0x10000 * 0x10000
	set S[T] = length / 0x100
	set T = T + 1
	set S[T] = length - length / 0x100 * 0x100
	set T = T + 1
	set index = 0
	set AA = A()
	set BB = B()
	set CC = C()
	set DD = D()
	loop
		exitwhen index + 64 > T
		set indexEnd = 0
		loop
			exitwhen indexEnd == 64
			set M[indexEnd / 4] = M[indexEnd / 4] * 256 + S[index + indexEnd]
			set indexEnd = indexEnd + 1
		endloop
		set a = AA
		set b = BB
		set c = CC
		set d = DD
		//第一轮
		set a = b + ((a + (F(b, c, d) + M[0] + 0xd76aa478)) * R2I(Pow(2, 7)))
		set d = a + ((d + (F(a, b, c) + M[1] + 0xe8c7b756)) * R2I(Pow(2, 12)))
		set c = d + ((c + (F(d, a, b) + M[2] + 0x242070db)) * R2I(Pow(2, 17)))
		set b = c + ((b + (F(c, d, a) + M[3] + 0xc1bdceee)) * R2I(Pow(2, 22)))
		set a = b + ((a + (F(b, c, d) + M[4] + 0xf57c0faf)) * R2I(Pow(2, 7)))
		set d = a + ((d + (F(a, b, c) + M[5] + 0x4787c62a)) * R2I(Pow(2, 12)))
		set c = d + ((c + (F(d, a, b) + M[6] + 0xa8304613)) * R2I(Pow(2, 17)))
		set b = c + ((b + (F(c, d, a) + M[7] + 0xfd469501)) * R2I(Pow(2, 22)))
		set a = b + ((a + (F(b, c, d) + M[8] + 0x698098d8)) * R2I(Pow(2, 7)))
		set d = a + ((d + (F(a, b, c) + M[9] + 0x8b44f7af)) * R2I(Pow(2, 12)))
		set c = d + ((c + (F(d, a, b) + M[10] + 0xffff5bb1)) * R2I(Pow(2, 17)))
		set b = c + ((b + (F(c, d, a) + M[11] + 0x895cd7be)) * R2I(Pow(2, 22)))
		set a = b + ((a + (F(b, c, d) + M[12] + 0x6b901122)) * R2I(Pow(2, 7)))
		set d = a + ((d + (F(a, b, c) + M[13] + 0xfd987193)) * R2I(Pow(2, 12)))
		set c = d + ((c + (F(d, a, b) + M[14] + 0xa679438e)) * R2I(Pow(2, 17)))
		set b = c + ((b + (F(c, d, a) + M[15] + 0x49b40821)) * R2I(Pow(2, 22)))
		//第二轮
		set a = b + ((a + (G(b, c, d) + M[1] + 0xf61e2562)) * R2I(Pow(2, 5)))
		set d = a + ((d + (G(a, b, c) + M[6] + 0xc040b340)) * R2I(Pow(2, 9)))
		set c = d + ((c + (G(d, a, b) + M[11] + 0x265e5a51)) * R2I(Pow(2, 14)))
		set b = c + ((b + (G(c, d, a) + M[0] + 0xe9b6c7aa)) * R2I(Pow(2, 20)))
		set a = b + ((a + (G(b, c, d) + M[5] + 0xd62f105d)) * R2I(Pow(2, 5)))
		set d = a + ((d + (G(a, b, c) + M[10] + 0x02441453)) * R2I(Pow(2, 9)))
		set c = d + ((c + (G(d, a, b) + M[15] + 0xd8a1e681)) * R2I(Pow(2, 14)))
		set b = c + ((b + (G(c, d, a) + M[4] + 0xe7d3fbc8)) * R2I(Pow(2, 20)))
		set a = b + ((a + (G(b, c, d) + M[9] + 0x21e1cde6)) * R2I(Pow(2, 5)))
		set d = a + ((d + (G(a, b, c) + M[14] + 0xc33707d6)) * R2I(Pow(2, 9)))
		set c = d + ((c + (G(d, a, b) + M[3] + 0xf4d50d87)) * R2I(Pow(2, 14)))
		set b = c + ((b + (G(c, d, a) + M[8] + 0x455a14ed)) * R2I(Pow(2, 20)))
		set a = b + ((a + (G(b, c, d) + M[13] + 0xa9e3e905)) * R2I(Pow(2, 5)))
		set d = a + ((d + (G(a, b, c) + M[2] + 0xfcefa3f8)) * R2I(Pow(2, 9)))
		set c = d + ((c + (G(d, a, b) + M[7] + 0x676f02d9)) * R2I(Pow(2, 14)))
		set b = c + ((b + (G(c, d, a) + M[12] + 0x8d2a4c8a)) * R2I(Pow(2, 20)))
		//第三轮
		set a = b + ((a + (H(b, c, d) + M[5] + 0xfffa3942)) * R2I(Pow(2, 4)))
		set d = a + ((d + (H(a, b, c) + M[8] + 0x8771f681)) * R2I(Pow(2, 11)))
		set c = d + ((c + (H(d, a, b) + M[11] + 0x6d9d6122)) * R2I(Pow(2, 16)))
		set b = c + ((b + (H(c, d, a) + M[14] + 0xfde5380c)) * R2I(Pow(2, 23)))
		set a = b + ((a + (H(b, c, d) + M[1] + 0xa4beea44)) * R2I(Pow(2, 4)))
		set d = a + ((d + (H(a, b, c) + M[4] + 0x4bdecfa9)) * R2I(Pow(2, 11)))
		set c = d + ((c + (H(d, a, b) + M[7] + 0xf6bb4b60)) * R2I(Pow(2, 16)))
		set b = c + ((b + (H(c, d, a) + M[10] + 0xbebfbc70)) * R2I(Pow(2, 23)))
		set a = b + ((a + (H(b, c, d) + M[13] + 0x289b7ec6)) * R2I(Pow(2, 4)))
		set d = a + ((d + (H(a, b, c) + M[0] + 0xeaa127fa)) * R2I(Pow(2, 11)))
		set c = d + ((c + (H(d, a, b) + M[3] + 0xd4ef3085)) * R2I(Pow(2, 16)))
		set b = c + ((b + (H(c, d, a) + M[6] + 0x04881d05)) * R2I(Pow(2, 23)))
		set a = b + ((a + (H(b, c, d) + M[9] + 0xd9d4d039)) * R2I(Pow(2, 4)))
		set d = a + ((d + (H(a, b, c) + M[12] + 0xe6db99e5)) * R2I(Pow(2, 11)))
		set c = d + ((c + (H(d, a, b) + M[15] + 0x1fa27cf8)) * R2I(Pow(2, 16)))
		set b = c + ((b + (H(c, d, a) + M[2] + 0xc4ac5665)) * R2I(Pow(2, 23)))
		//第四轮
		set a = b + ((a + (I(b, c, d) + M[0] + 0xf4292244)) * R2I(Pow(2, 6)))
		set d = a + ((d + (I(a, b, c) + M[7] + 0x432aff97)) * R2I(Pow(2, 10)))
		set c = d + ((c + (I(d, a, b) + M[14] + 0xab9423a7)) * R2I(Pow(2, 15)))
		set b = c + ((b + (I(c, d, a) + M[5] + 0xfc93a039)) * R2I(Pow(2, 21)))
		set a = b + ((a + (I(b, c, d) + M[12] + 0x655b59c3)) * R2I(Pow(2, 6)))
		set d = a + ((d + (I(a, b, c) + M[3] + 0x8f0ccc92)) * R2I(Pow(2, 10)))
		set c = d + ((c + (I(d, a, b) + M[10] + 0xffeff47d)) * R2I(Pow(2, 15)))
		set b = c + ((b + (I(c, d, a) + M[1] + 0x85845dd1)) * R2I(Pow(2, 21)))
		set a = b + ((a + (I(b, c, d) + M[8] + 0x6fa87e4f)) * R2I(Pow(2, 6)))
		set d = a + ((d + (I(a, b, c) + M[15] + 0xfe2ce6e0)) * R2I(Pow(2, 10)))
		set c = d + ((c + (I(d, a, b) + M[6] + 0xa3014314)) * R2I(Pow(2, 15)))
		set b = c + ((b + (I(c, d, a) + M[13] + 0x4e0811a1)) * R2I(Pow(2, 21)))
		set a = b + ((a + (I(b, c, d) + M[4] + 0xf7537e82)) * R2I(Pow(2, 6)))
		set d = a + ((d + (I(a, b, c) + M[11] + 0xbd3af235)) * R2I(Pow(2, 10)))
		set c = d + ((c + (I(d, a, b) + M[2] + 0x2ad7d2bb)) * R2I(Pow(2, 15)))
		set b = c + ((b + (I(c, d, a) + M[9] + 0xeb86d391)) * R2I(Pow(2, 21)))

		set AA = AA + a
		set BB = BB + b
		set CC = CC + c
		set DD = DD + d
		set index = index + 64
	endloop
	set result[0] = AA
	set result[1] = BB
	set result[2] = CC
	set result[3] = DD
	set r = ""
	set index = 0
	loop
		exitwhen index == 4
		set r = r + HexString(IAbsBJ(result[index]))
		set index = index + 1
	endloop
	return r
endfunction

endlibrary